﻿using System;
using System.Reflection;

namespace Nomo.CoreModule
{
    /// <summary>
    /// 反射帮助类。
    /// </summary>
    public static class ReflectionHelper
    {
        /// <summary>
        /// 获取字段的值。
        /// </summary>
        /// <param name="obj">对象。</param>
        /// <param name="name">字段名。</param>
        /// <returns>字段的值。</returns>
        /// <exception cref="ArgumentNullException"><paramref name="obj"/> 为 <see langword="null"/> .</exception>
        /// <exception cref="InvalidOperationException">找不到名为 <paramref name="name"/> 的字段信息。</exception>
        public static object GetFieldValue(this object obj, string name)
        {
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }
            var memberInfo = obj.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            if (memberInfo == null)
            {
                throw new InvalidOperationException();
            }
            return memberInfo.GetValue(obj);
        }

        /// <summary>
        /// 设置字段的值。
        /// </summary>
        /// <param name="obj">对象。</param>
        /// <param name="name">字段名。</param>
        /// <param name="value">要设置的值。</param>
        /// <exception cref="ArgumentNullException"><paramref name="obj"/> 为 <see langword="null"/> .</exception>
        /// <exception cref="InvalidOperationException">找不到名为 <paramref name="name"/> 的字段信息。</exception>
        public static void SetFieldValue(this object obj, string name, object value)
        {
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }
            var memberInfo = obj.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            if (memberInfo == null)
            {
                throw new InvalidOperationException();
            }
            memberInfo.SetValue(obj, value);
        }

        /// <summary>
        /// 获取属性的值。
        /// </summary>
        /// <param name="obj">对象。</param>
        /// <param name="name">属性名。</param>
        /// <returns>属性的值。</returns>
        /// <exception cref="ArgumentNullException"><paramref name="obj"/> 为 <see langword="null"/> .</exception>
        /// <exception cref="InvalidOperationException">找不到名为 <paramref name="name"/> 的属性信息。</exception>
        public static object GetPropertyValue(this object obj, string name)
        {
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }
            var memberInfo = obj.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            if (memberInfo == null)
            {
                throw new InvalidOperationException();
            }
            return memberInfo.GetValue(obj);
        }


        /// <summary>
        /// 设置属性的值。
        /// </summary>
        /// <param name="obj">对象。</param>
        /// <param name="name">属性名。</param>
        /// <param name="value">要设置的值。</param>
        /// <exception cref="ArgumentNullException"><paramref name="obj"/> 为 <see langword="null"/> .</exception>
        /// <exception cref="InvalidOperationException">找不到名为 <paramref name="name"/> 的属性信息。</exception>
        public static void SetPropertyValue(this object obj, string name, object value)
        {
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }
            var memberInfo = obj.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            if (memberInfo == null)
            {
                throw new InvalidOperationException();
            }
            memberInfo.SetValue(obj, value);
        }

        /// <summary>
        /// 获取字段的值。
        /// </summary>
        /// <param name="type">类型。</param>
        /// <param name="name">字段名。</param>
        /// <returns>字段的值。</returns>
        /// <exception cref="ArgumentNullException"><paramref name="type"/> 为 <see langword="null"/> .</exception>
        /// <exception cref="InvalidOperationException">找不到名为 <paramref name="name"/> 的字段信息。</exception>
        public static object GetFieldValue(this Type type, string name)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            var memberInfo = type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
            if (memberInfo == null)
            {
                throw new InvalidOperationException();
            }
            return memberInfo.GetValue(name);
        }

        /// <summary>
        /// 设置字段的值。
        /// </summary>
        /// <param name="type">类型。</param>
        /// <param name="name">字段名。</param>
        /// <param name="value">要设置的值。</param>
        /// <exception cref="ArgumentNullException"><paramref name="type"/> 为 <see langword="null"/> .</exception>
        /// <exception cref="InvalidOperationException">找不到名为 <paramref name="name"/> 的字段信息。</exception>
        public static void SetFieldValue(this Type type, string name, object value)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            var memberInfo = type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
            if (memberInfo == null)
            {
                throw new InvalidOperationException();
            }
            memberInfo.SetValue(name, value);
        }


        /// <summary>
        /// 获取属性的值。
        /// </summary>
        /// <param name="type">类型。</param>
        /// <param name="name">属性名。</param>
        /// <returns>字段的值。</returns>
        /// <exception cref="ArgumentNullException"><paramref name="type"/> 为 <see langword="null"/> .</exception>
        /// <exception cref="InvalidOperationException">找不到名为 <paramref name="name"/> 的属性信息。</exception>
        public static object GetPropertyValue(this Type type, string name)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            var memberInfo = type.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
            if (memberInfo == null)
            {
                throw new InvalidOperationException();
            }
            return memberInfo.GetValue(name);
        }


        /// <summary>
        /// 设置属性的值。
        /// </summary>
        /// <param name="type">类型。</param>
        /// <param name="name">属性名。</param>
        /// <param name="value">要设置的值。</param>
        /// <exception cref="ArgumentNullException"><paramref name="type"/> 为 <see langword="null"/> .</exception>
        /// <exception cref="InvalidOperationException">找不到名为 <paramref name="name"/> 的属性信息。</exception>
        public static void SetPropertyValue(this Type type, string name, object value)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            var memberInfo = type.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
            if (memberInfo == null)
            {
                throw new InvalidOperationException();
            }
            memberInfo.SetValue(name, value);
        }
    }
}
